import pyciv.action
import pyciv.resources
import pyciv.terrain

class Worker(object):
    def __init__(self, name, income, upkeep):
        self.name = name
        self._income = income
        self._upkeep = upkeep
        self.ready_for_action = False
        
    def _move_or_switch(self, hex, engine):
        if engine.state.worker[hex] == pyciv.worker.NONE:
            return pyciv.action.Move(hex=hex)
        else:
            enabled=engine.state.worker[hex].ready_for_action
            if enabled:
                reason="Switch workers"
            else:
                reason="Already moved"
            return pyciv.action.Switch(hex,
                                       enabled=enabled,
                                       reason=reason)

    def _influence_or_conquer(self, hex, engine):
        if not engine.state.terrain[hex].valid:
            return pyciv.action.Influence(hex,
                                          enabled=False, 
                                          reason="Terrain is impassible.")

        myinfluence = engine.sum_for_player(hex, engine.current_player(), 
                                            pyciv.resources.INFLUENCE)
        enemyinfluence = engine.sum_for_player(hex, engine.state.owner[hex], 
                                               pyciv.resources.INFLUENCE)     
        reason = "Influence: %d (you) vs. %d (enemy)" % (myinfluence, enemyinfluence)
        return pyciv.action.Influence(hex, 
                                      enabled=(myinfluence > enemyinfluence), 
                                      reason=reason)

    def generate_hex_action(self, hex, engine):
        if self.ready_for_action and not hex == engine.current_hex:
            if engine.current_player_owns(hex):
                return self._move_or_switch(hex, engine)
            elif engine.next_to_current_hex(hex):
                return self._influence_or_conquer(hex, engine)
        return pyciv.action.NONE
    
    def generate_actions(self, current_hex, engine):
        reason = pyciv.resources.long_string(engine.state.worker[current_hex].upkeep(),
                                             text="Sell for ")
        return [pyciv.action.SellWorker(current_hex, reason=reason)]

    def income(self, terrain):
        return self._income[terrain]

    def upkeep(self):
        return self._upkeep

class Empty(Worker):
    def __init__(self):
        income = {pyciv.terrain.FIELDS: {},
                  pyciv.terrain.FOREST: {},
                  pyciv.terrain.MOUNTAIN: {},
                  pyciv.terrain.TOWN: {}}
        upkeep = {}
        Worker.__init__(self, "", income, upkeep)

    def generate_hex_action(self, hex, engine):
        return pyciv.action.NONE
    
    def generate_actions(self, current_hex, engine):
        actions = []
        if engine.current_player_owns(current_hex) and engine.state.terrain[current_hex].valid:
            actions.append(pyciv.action.CreateNewWorker(current_hex, engine, Farmer()))
            actions.append(pyciv.action.CreateNewWorker(current_hex, engine, Merchant()))
            actions.append(pyciv.action.CreateNewWorker(current_hex, engine, Priest()))
            actions.append(pyciv.action.CreateNewWorker(current_hex, engine, Soldier()))
        return actions

class Farmer(Worker):
    def __init__(self):
        income = {pyciv.terrain.FIELDS: {pyciv.resources.FOOD: 3, 
                                         pyciv.resources.INFLUENCE: 1},
                  pyciv.terrain.FOREST: {pyciv.resources.FOOD: 2, 
                                         pyciv.resources.INFLUENCE: 1},
                  pyciv.terrain.MOUNTAIN: {pyciv.resources.INFLUENCE: 1},
                  pyciv.terrain.TOWN: {pyciv.resources.INFLUENCE: 1}}
        upkeep = {pyciv.resources.GOLD: 1,
                  pyciv.resources.FOOD: 0}
        Worker.__init__(self, "Farmer", income, upkeep)

    def _influence_or_conquer(self, hex, engine):
        if engine.state.worker[hex] is not pyciv.worker.NONE:
            return pyciv.action.Influence(enabled=False, reason="Can only influence empty hexes.")
        return Worker._influence_or_conquer(self, hex, engine)

class Merchant(Worker):
    def __init__(self):
        income = {pyciv.terrain.FIELDS: {pyciv.resources.GOLD: 2,
                                         pyciv.resources.INFLUENCE: 1},
                  pyciv.terrain.FOREST: {pyciv.resources.GOLD: 2,
                                         pyciv.resources.INFLUENCE: 1},
                  pyciv.terrain.MOUNTAIN: {pyciv.resources.GOLD: 1,
                                           pyciv.resources.INFLUENCE: 1},
                  pyciv.terrain.TOWN: {pyciv.resources.GOLD: 4,
                                       pyciv.resources.INFLUENCE: 1}}
        upkeep = {pyciv.resources.FOOD: 1,
                  pyciv.resources.GOLD: 0}
        Worker.__init__(self, "Merchant", income, upkeep)

    def _influence_or_conquer(self, hex, engine):
        if engine.state.worker[hex] is not pyciv.worker.NONE:
            return pyciv.action.Influence(hex, 
                                          enabled=False, 
                                          reason="Can only influence empty hexes.")
        return Worker._influence_or_conquer(self, hex, engine)

class Priest(Worker):
    def __init__(self):
        Worker.__init__(self, "Priest", 
                        income={pyciv.resources.INFLUENCE: 3},
                        upkeep={pyciv.resources.FOOD: 1,
                                pyciv.resources.GOLD: 0})
                  
    def income(self, terrain):
        return self._income

class Soldier(Worker):
    def __init__(self):
        Worker.__init__(self, "Soldier", 
                        income={pyciv.resources.POWER: 3,
                                pyciv.resources.INFLUENCE: 1},
                        upkeep={pyciv.resources.FOOD: 1,
                                pyciv.resources.GOLD: 1})

    def income(self, terrain):
        return self._income

    def _influence_or_conquer(self, hex, engine):
        if not engine.state.terrain[hex].valid:
            return pyciv.action.Conquer(hex,
                                        enabled=False, 
                                        reason="Bad terrain")
        mypower = engine.sum_for_player(hex, engine.current_player(), 
                                        pyciv.resources.POWER)
        enemypower = engine.sum_for_player(hex, engine.state.owner[hex], 
                                           pyciv.resources.POWER)     
        reason = "%d vs. %d" % (mypower, enemypower)
        return pyciv.action.Conquer(hex, 
                                    enabled=(mypower > enemypower), 
                                    reason=reason)

NONE = Empty()
